package sc.prototype.pfs.test.eventnotify.server;

import static org.jboss.netty.channel.Channels.pipeline;
import static org.jboss.netty.handler.codec.http.HttpHeaders.isKeepAlive;
import static org.jboss.netty.handler.codec.http.HttpHeaders.Names.CONNECTION;
import static org.jboss.netty.handler.codec.http.HttpHeaders.Names.CONTENT_LENGTH;

import java.net.InetSocketAddress;
import java.util.concurrent.Executors;

import org.jboss.netty.bootstrap.ServerBootstrap;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.channel.ChannelFuture;
import org.jboss.netty.channel.ChannelFutureListener;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.channel.ExceptionEvent;
import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.channel.SimpleChannelUpstreamHandler;
import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
import org.jboss.netty.handler.codec.http.HttpContentCompressor;
import org.jboss.netty.handler.codec.http.HttpHeaders;
import org.jboss.netty.handler.codec.http.HttpRequest;
import org.jboss.netty.handler.codec.http.HttpRequestDecoder;
import org.jboss.netty.handler.codec.http.HttpResponse;
import org.jboss.netty.handler.codec.http.HttpResponseEncoder;

public class MockServer {

    public MockServer(int port, RequestHandler handler) {
        this.port = port;
        this.handler = handler;
    }

    int port;

    RequestHandler handler;

    public void run() {
        // Configure the server.
        ServerBootstrap bootstrap = new ServerBootstrap(new NioServerSocketChannelFactory(
                Executors.newCachedThreadPool(), Executors.newCachedThreadPool()));

        // Set up the event pipeline factory.
        bootstrap.setPipelineFactory(new ChannelPipelineFactory() {

            @Override
            public ChannelPipeline getPipeline() throws Exception {
                ChannelPipeline pipeline = pipeline();
                // Uncomment the following line if you want HTTPS
                //SSLEngine engine = SecureChatSslContextFactory.getServerContext().createSSLEngine();
                //engine.setUseClientMode(false);
                //pipeline.addLast("ssl", new SslHandler(engine));
                pipeline.addLast("decoder", new HttpRequestDecoder());
                // Uncomment the following line if you don't want to handle HttpChunks.
                //pipeline.addLast("aggregator", new HttpChunkAggregator(1048576));
                pipeline.addLast("encoder", new HttpResponseEncoder());
                // Remove the following line if you don't want automatic content compression.
                pipeline.addLast("deflater", new HttpContentCompressor());
                pipeline.addLast("handler", new HttpServerHandler(handler));
                return pipeline;
            }
        });

        // Bind and start to accept incoming connections.
        bootstrap.bind(new InetSocketAddress(port));
    }

    public static class HttpServerHandler extends SimpleChannelUpstreamHandler {

        public HttpServerHandler(RequestHandler handler) {
            super();
            this.handler = handler;
        }

        RequestHandler handler;

        @Override
        public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
            HttpRequest request = (HttpRequest) e.getMessage();
            ChannelBuffer content = request.getContent();
            if (content.readable()) {
                HttpResponse response = handler.httpRequestReceived(request);
                // Decide whether to close the connection or not.
                boolean keepAlive = isKeepAlive(request);
                if (keepAlive) {
                    // Add 'Content-Length' header only for a keep-alive connection.
                    response.setHeader(CONTENT_LENGTH, response.getContent().readableBytes());
                    // Add keep alive header as per:
                    // - http://www.w3.org/Protocols/HTTP/1.1/draft-ietf-http-v11-spec-01.html#Connection
                    response.setHeader(CONNECTION, HttpHeaders.Values.KEEP_ALIVE);
                }

                // Write the response.
                ChannelFuture future = e.getChannel().write(response);

                // Close the non-keep-alive connection after the write operation is done.
                if (!keepAlive) {
                    future.addListener(ChannelFutureListener.CLOSE);
                }
            }
        }

        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception {
            e.getChannel().close();
            throw new Exception(e.getCause());
        }
    }
}
